#include "gap_gatts_internal.h"

extern struct configure configure;

uint8_t adv_config_done = 0;

esp_ble_adv_params_t adv_params = {
	.adv_int_min = 0x20,
	.adv_int_max = 0x40,
	.adv_type = ADV_TYPE_IND,
	.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
	.channel_map = ADV_CHNL_ALL,
	.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};

esp_err_t bt_init()
{
	esp_err_t ret;

	ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));

	esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();

	ret = esp_bt_controller_init(&bt_cfg);
	if (ret) {
		ESP_LOGE(GATTS_TAG, "%s enable controller failed: %s", __func__,
			 esp_err_to_name(ret));
		return ret;
	}

	ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
	if (ret) {
		ESP_LOGE(GATTS_TAG, "%s enable controller failed: %s", __func__,
			 esp_err_to_name(ret));
		return ret;
	}

	ret = esp_bluedroid_init();
	if (ret) {
		ESP_LOGE(GATTS_TAG, "%s init bluetooth failed: %s", __func__,
			 esp_err_to_name(ret));
		return ret;
	}

	ret = esp_bluedroid_enable();
	if (ret) {
		ESP_LOGE(GATTS_TAG, "%s enable bluetooth failed: %s", __func__,
			 esp_err_to_name(ret));
		return ret;
	}
	return ret;
}

void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
			 esp_ble_gatts_cb_param_t *param)
{
	/* If event is register event, store the gatts_if for each profile */
	if (event == ESP_GATTS_REG_EVT) {
		if (param->reg.status == ESP_GATT_OK) {
			configure.gatts_if = gatts_if;
		} else {
			ESP_LOGE(GATTS_TAG,
				 "reg app failed, app_id %04x, status %d",
				 param->reg.app_id, param->reg.status);
			return;
		}
		// reg_handler(event, gatts_if, param);
	}
	do {
		/* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every
       * profile cb function */
		if (gatts_if == ESP_GATT_IF_NONE ||
		    gatts_if == configure.gatts_if) {
			gatts_profile_event_handler(event, gatts_if, param);
		}

	} while (0);
}

void gap_event_handler(esp_gap_ble_cb_event_t event,
		       esp_ble_gap_cb_param_t *param)
{
	switch (event) {
#ifdef CONFIG_SET_RAW_ADV_DATA
	case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:
		adv_config_done &= (~ADV_CONFIG_FLAG);
		if (adv_config_done == 0) {
			esp_ble_gap_start_advertising(&adv_params);
		}
		break;
	case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT:
		adv_config_done &= (~SCAN_RSP_CONFIG_FLAG);
		if (adv_config_done == 0) {
			esp_ble_gap_start_advertising(&adv_params);
		}
		break;
#else
	case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
		adv_config_done &= (~ADV_CONFIG_FLAG);
		if (adv_config_done == 0) {
			esp_ble_gap_start_advertising(&adv_params);
		}
		break;
	case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT:
		adv_config_done &= (~SCAN_RSP_CONFIG_FLAG);
		if (adv_config_done == 0) {
			esp_ble_gap_start_advertising(&adv_params);
		}
		break;
#endif
	case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
		/* advertising start complete event to indicate advertising start
     * successfully or failed */
		if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
			ESP_LOGE(GATTS_TAG, "advertising start failed");
		} else {
			ESP_LOGI(GATTS_TAG, "advertising start successfully");
		}
		break;
	case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
		if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) {
			ESP_LOGE(GATTS_TAG, "Advertising stop failed");
		} else {
			ESP_LOGI(GATTS_TAG, "Stop adv successfully\n");
		}
		break;
	case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
		ESP_LOGI(
			GATTS_TAG,
			"update connection params status = %d, min_int = %d, max_int = "
			"%d,conn_int = %d,latency = %d, timeout = %d",
			param->update_conn_params.status,
			param->update_conn_params.min_int,
			param->update_conn_params.max_int,
			param->update_conn_params.conn_int,
			param->update_conn_params.latency,
			param->update_conn_params.timeout);
		break;
	default:
		break;
	}
}

esp_err_t gap_gatts_register()
{
	esp_err_t ret;

	ret = bt_init();
	ESP_ERROR_CHECK(ret);

	ret = esp_ble_gatts_register_callback(gatts_event_handler);
	if (ret) {
		ESP_LOGE(GATTS_TAG, "gatts register error, error code = %x",
			 ret);
		return ret;
	}

	ret = esp_ble_gap_register_callback(gap_event_handler);
	if (ret) {
		ESP_LOGE(GATTS_TAG, "gap register error, error code = %x", ret);
		return ret;
	}

	ret = esp_ble_gatts_app_register(0x55);
	if (ret) {
		ESP_LOGE(GATTS_TAG, "gatts app register error, error code = %x",
			 ret);
		return ret;
	}

	ret = esp_ble_gatt_set_local_mtu(500);
	if (ret) {
		ESP_LOGE(GATTS_TAG, "set local  MTU failed, error code = %x",
			 ret);
		return ret;
	}
	return ret;
}

esp_err_t gap_gatts_unregister()
{
	esp_err_t ret;

	ret = esp_ble_gatts_app_unregister(configure.gatts_if);
	if (ret) {
		ESP_LOGE(GATTS_TAG, "gatts app register error, error code = %x",
			 ret);
		return ret;
	}
	return ret;
}